"""
企业级金融数据MCP服务系统 - 期权数据模型
提供完整的期权相关数据SQLAlchemy ORM模型定义
"""

from datetime import datetime, date
from decimal import Decimal
from typing import Optional, Dict, Any
from sqlalchemy import String, DateTime, Date, Boolean, Integer, Numeric, Text, Index, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.dialects.postgresql import JSONB

from .base import BaseFinancialModel, DataVersionMixin, SyncStatusMixin, PartitionMixin


class OptionBasicInfo(BaseFinancialModel, SyncStatusMixin):
    """
    期权基本信息模型
    存储期权合约的基础信息，如合约代码、标的资产、行权价等
    """
    __tablename__ = "option_basic_info"
    
    # 期权合约代码
    option_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="期权合约代码")
    
    # 期权合约名称
    option_name: Mapped[str] = mapped_column(String(100), nullable=False, comment="期权合约名称")
    
    # 标的资产代码
    underlying_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="标的资产代码")
    
    # 标的资产名称
    underlying_name: Mapped[str] = mapped_column(String(100), nullable=False, comment="标的资产名称")
    
    # 标的资产类型：股票, ETF, 期货, 指数等
    underlying_type: Mapped[str] = mapped_column(String(20), nullable=False, comment="标的资产类型")
    
    # 交易所代码：SSE(上交所), SZSE(深交所), SHFE(上期所), DCE(大商所), CZCE(郑商所), CFFEX(中金所)
    exchange: Mapped[str] = mapped_column(String(10), nullable=False, comment="交易所代码")
    
    # 期权类型：认购期权(Call), 认沽期权(Put)
    option_type: Mapped[str] = mapped_column(String(10), nullable=False, comment="期权类型")
    
    # 行权价格
    strike_price: Mapped[Decimal] = mapped_column(Numeric(12, 4), nullable=False, comment="行权价格")
    
    # 合约单位
    contract_unit: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="合约单位")
    
    # 行权方式：欧式, 美式
    exercise_style: Mapped[Optional[str]] = mapped_column(String(10), nullable=True, comment="行权方式")
    
    # 交割方式：实物交割, 现金交割
    delivery_method: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="交割方式")
    
    # 最小报价单位
    min_price_change: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="最小报价单位")
    
    # 涨跌停板幅度(%)
    price_limit: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="涨跌停板幅度(%)")
    
    # 保证金比例(%)
    margin_ratio: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="保证金比例(%)")
    
    # 上市日期
    list_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="上市日期")
    
    # 到期日期
    expire_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="到期日期")
    
    # 行权日期
    exercise_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="行权日期")
    
    # 最后交易日
    last_trade_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="最后交易日")
    
    # 合约状态：上市, 交易, 停牌, 到期, 退市
    contract_status: Mapped[str] = mapped_column(String(20), nullable=False, default="上市", comment="合约状态")
    
    # 是否为主力合约
    is_main: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, comment="是否为主力合约")
    
    # 扩展信息
    extra_info: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="扩展信息")
    
    __table_args__ = (
        UniqueConstraint('option_code', 'exchange', name='uk_option_basic_code_exchange'),
        Index('idx_option_basic_code', 'option_code'),
        Index('idx_option_basic_underlying', 'underlying_code'),
        Index('idx_option_basic_exchange', 'exchange'),
        Index('idx_option_basic_type', 'option_type'),
        Index('idx_option_basic_strike', 'strike_price'),
        Index('idx_option_basic_expire_date', 'expire_date'),
        Index('idx_option_basic_status', 'contract_status'),
        Index('idx_option_basic_main', 'is_main'),
        Index('idx_option_basic_underlying_type_strike', 'underlying_code', 'option_type', 'strike_price'),
    )
    
    def __repr__(self) -> str:
        return f"<OptionBasicInfo(option_code={self.option_code}, underlying_code={self.underlying_code}, option_type={self.option_type}, strike_price={self.strike_price})>"


class OptionDailyData(BaseFinancialModel, PartitionMixin):
    """
    期权日线数据模型
    存储期权合约的日K线数据，包括开高低收、成交量、持仓量、隐含波动率等
    """
    __tablename__ = "option_daily_data"
    
    # 期权合约代码
    option_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="期权合约代码")
    
    # 交易日期
    trade_date: Mapped[date] = mapped_column(Date, nullable=False, comment="交易日期")
    
    # 开盘价
    open_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="开盘价")
    
    # 最高价
    high_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="最高价")
    
    # 最低价
    low_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="最低价")
    
    # 收盘价
    close_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="收盘价")
    
    # 结算价
    settle_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="结算价")
    
    # 前收盘价
    pre_close: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="前收盘价")
    
    # 前结算价
    pre_settle: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="前结算价")
    
    # 涨跌额
    change: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="涨跌额")
    
    # 涨跌幅(%)
    pct_chg: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="涨跌幅(%)")
    
    # 成交量（张）
    volume: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="成交量(张)")
    
    # 成交额（万元）
    amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="成交额(万元)")
    
    # 持仓量（张）
    open_interest: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="持仓量(张)")
    
    # 持仓量变化
    oi_change: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="持仓量变化")
    
    # 标的收盘价
    underlying_close: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="标的收盘价")
    
    # 隐含波动率(%)
    implied_volatility: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="隐含波动率(%)")
    
    # Delta值
    delta: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="Delta值")
    
    # Gamma值
    gamma: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="Gamma值")
    
    # Theta值
    theta: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="Theta值")
    
    # Vega值
    vega: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="Vega值")
    
    # Rho值
    rho: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="Rho值")
    
    # 内在价值
    intrinsic_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="内在价值")
    
    # 时间价值
    time_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="时间价值")
    
    # 到期天数
    days_to_expire: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="到期天数")
    
    __table_args__ = (
        UniqueConstraint('option_code', 'trade_date', name='uk_option_daily_code_date'),
        Index('idx_option_daily_code', 'option_code'),
        Index('idx_option_daily_date', 'trade_date'),
        Index('idx_option_daily_code_date', 'option_code', 'trade_date'),
        Index('idx_option_daily_volume', 'volume'),
        Index('idx_option_daily_open_interest', 'open_interest'),
        Index('idx_option_daily_iv', 'implied_volatility'),
        # 分区索引
        Index('idx_option_daily_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<OptionDailyData(option_code={self.option_code}, trade_date={self.trade_date}, close_price={self.close_price})>"


class OptionMinuteData(BaseFinancialModel, PartitionMixin):
    """
    期权分钟数据模型
    存储期权合约的分钟级数据
    """
    __tablename__ = "option_minute_data"
    
    # 期权合约代码
    option_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="期权合约代码")
    
    # 交易时间
    trade_time: Mapped[datetime] = mapped_column(DateTime, nullable=False, comment="交易时间")
    
    # 开盘价
    open_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="开盘价")
    
    # 最高价
    high_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="最高价")
    
    # 最低价
    low_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="最低价")
    
    # 收盘价
    close_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="收盘价")
    
    # 成交量（张）
    volume: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="成交量(张)")
    
    # 成交额（万元）
    amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="成交额(万元)")
    
    # 持仓量（张）
    open_interest: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="持仓量(张)")
    
    # 标的价格
    underlying_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="标的价格")
    
    __table_args__ = (
        UniqueConstraint('option_code', 'trade_time', name='uk_option_minute_code_time'),
        Index('idx_option_minute_code', 'option_code'),
        Index('idx_option_minute_time', 'trade_time'),
        Index('idx_option_minute_code_time', 'option_code', 'trade_time'),
        # 分区索引
        Index('idx_option_minute_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<OptionMinuteData(option_code={self.option_code}, trade_time={self.trade_time}, close_price={self.close_price})>"


class OptionChain(BaseFinancialModel, PartitionMixin):
    """
    期权链数据模型
    存储某个标的资产在特定日期的所有期权合约信息
    """
    __tablename__ = "option_chain"
    
    # 标的资产代码
    underlying_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="标的资产代码")
    
    # 交易日期
    trade_date: Mapped[date] = mapped_column(Date, nullable=False, comment="交易日期")
    
    # 到期月份
    expire_month: Mapped[str] = mapped_column(String(10), nullable=False, comment="到期月份")
    
    # 行权价格
    strike_price: Mapped[Decimal] = mapped_column(Numeric(12, 4), nullable=False, comment="行权价格")
    
    # 认购期权代码
    call_code: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="认购期权代码")
    
    # 认购期权价格
    call_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="认购期权价格")
    
    # 认购期权成交量
    call_volume: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="认购期权成交量")
    
    # 认购期权持仓量
    call_open_interest: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="认购期权持仓量")
    
    # 认购期权隐含波动率
    call_iv: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="认购期权隐含波动率")
    
    # 认沽期权代码
    put_code: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="认沽期权代码")
    
    # 认沽期权价格
    put_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="认沽期权价格")
    
    # 认沽期权成交量
    put_volume: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="认沽期权成交量")
    
    # 认沽期权持仓量
    put_open_interest: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="认沽期权持仓量")
    
    # 认沽期权隐含波动率
    put_iv: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="认沽期权隐含波动率")
    
    # 标的价格
    underlying_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="标的价格")
    
    # PCR比率（Put/Call Ratio）
    pcr_ratio: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="PCR比率")
    
    __table_args__ = (
        UniqueConstraint('underlying_code', 'trade_date', 'expire_month', 'strike_price', 
                        name='uk_option_chain_underlying_date_month_strike'),
        Index('idx_option_chain_underlying', 'underlying_code'),
        Index('idx_option_chain_date', 'trade_date'),
        Index('idx_option_chain_month', 'expire_month'),
        Index('idx_option_chain_strike', 'strike_price'),
        Index('idx_option_chain_call_code', 'call_code'),
        Index('idx_option_chain_put_code', 'put_code'),
        # 分区索引
        Index('idx_option_chain_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<OptionChain(underlying_code={self.underlying_code}, trade_date={self.trade_date}, strike_price={self.strike_price})>"


class OptionExerciseData(BaseFinancialModel, PartitionMixin):
    """
    期权行权数据模型
    存储期权合约的行权信息
    """
    __tablename__ = "option_exercise_data"
    
    # 期权合约代码
    option_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="期权合约代码")
    
    # 行权日期
    exercise_date: Mapped[date] = mapped_column(Date, nullable=False, comment="行权日期")
    
    # 行权数量（张）
    exercise_volume: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="行权数量(张)")
    
    # 行权比例(%)
    exercise_ratio: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="行权比例(%)")
    
    # 标的交割数量
    delivery_volume: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="标的交割数量")
    
    # 现金交割金额
    cash_settlement: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="现金交割金额")
    
    # 行权价格
    exercise_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="行权价格")
    
    # 标的价格
    underlying_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(12, 4), nullable=True, comment="标的价格")
    
    __table_args__ = (
        UniqueConstraint('option_code', 'exercise_date', name='uk_option_exercise_code_date'),
        Index('idx_option_exercise_code', 'option_code'),
        Index('idx_option_exercise_date', 'exercise_date'),
        Index('idx_option_exercise_volume', 'exercise_volume'),
        # 分区索引
        Index('idx_option_exercise_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<OptionExerciseData(option_code={self.option_code}, exercise_date={self.exercise_date}, exercise_volume={self.exercise_volume})>"


# 导出所有期权相关模型
__all__ = [
    'OptionBasicInfo',
    'OptionDailyData',
    'OptionMinuteData',
    'OptionChain',
    'OptionExerciseData',
]